package com.labot.service;

import java.util.Date;
import java.util.HashMap;
import java.util.List;
import java.util.Locale;
import java.util.Locale.Builder;
import java.util.Map;
import java.util.Map.Entry;

import javax.mail.MessagingException;
import javax.mail.internet.MimeMessage;

import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;
import org.apache.velocity.app.VelocityEngine;
import org.apache.velocity.exception.VelocityException;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.core.io.ByteArrayResource;
import org.springframework.core.io.ClassPathResource;
import org.springframework.mail.MailException;
import org.springframework.mail.MailSender;
import org.springframework.mail.SimpleMailMessage;
import org.springframework.mail.javamail.JavaMailSenderImpl;
import org.springframework.mail.javamail.MimeMessageHelper;
import org.springframework.ui.velocity.VelocityEngineUtils;

import com.labot.dao.MailTemplateDao;
import com.labot.model.MailTemplate;
import com.labot.model.User;
import com.labot.types.ConstantsType;
import com.labot.types.MailType;
import com.labot.webapp.listener.StartupListener;

/**
 * Class for sending e-mail messages based on Velocity templates
 * or with attachments.
 * 
 * @author Matt Raible
 */
public class MailEngine {
    private final Log log = LogFactory.getLog(MailEngine.class);
    private MailSender mailSender;
    private VelocityEngine velocityEngine;
    private String defaultFrom;
    
    @Autowired
    private MailTemplateDao mailTemplateDao;
    
    public MailEngine() {
		defaultFrom = StartupListener.getConfigValue(ConstantsType.MAIL_DEFAULT_FROM);
		if (defaultFrom == null) {
			defaultFrom = "no-reply@domain.com";
		}
	}

    public void setMailSender(MailSender mailSender) {
        this.mailSender = mailSender;
    }

    public MailSender getMailSender() {
        return mailSender;
    }

    public void setVelocityEngine(VelocityEngine velocityEngine) {
        this.velocityEngine = velocityEngine;
    }

    public void setFrom(String from) {
        this.defaultFrom = from;
    }

    /**
     * Send a simple message based on a Velocity template.
     * @param msg the message to populate
     * @param templateName the Velocity template to use (relative to classpath)
     * @param model a map containing key/value pairs
     */
    public void sendMessage(SimpleMailMessage msg, String templateName, Map model) {
        String result = null;

        try {
            result =
                VelocityEngineUtils.mergeTemplateIntoString(velocityEngine,
                                                            templateName, model);
        } catch (VelocityException e) {
            e.printStackTrace();
            log.error(e.getMessage());
        }
        
        msg.setText(result);
        send(msg);
    }
    
    public void sendMail(String subject, String body, String to) throws Exception {
    	if(StartupListener.isEnabledConfig(ConstantsType.TESTING_SYSTEM)) {
    		to = StartupListener.getConfigValue(ConstantsType.TESTING_EMAIL_RECIPIENT);
    	}
    	
    	MimeMessage mimeMessage = ((JavaMailSenderImpl) mailSender).createMimeMessage();
    	MimeMessageHelper msg = new MimeMessageHelper(mimeMessage, false, "utf-8");
    	msg.setFrom(defaultFrom);
    	msg.setTo(to);
    	msg.setSubject(subject);
    	msg.getMimeMessage().setText(body,  "utf-8", "text/html");
    	msg.setText(body, true);
    	msg.setSentDate(new Date());
    	
    	log.debug("Send email: " + subject + " to " + to);
    	
    	((JavaMailSenderImpl) mailSender).send(mimeMessage);
    }
    
    public void sendMail(MailType mail, String to, User user, Map<String, String> properties, Map<String, byte[]> attachments, Locale locale) throws Exception {
    	if(StartupListener.isEnabledConfig(ConstantsType.TESTING_SYSTEM)) {
    		to = StartupListener.getConfigValue(ConstantsType.TESTING_EMAIL_RECIPIENT);
    	}
    	
    	//Traer template
    	MailTemplate template = mailTemplateDao.getMailTemplate(mail);
    	if(template == null) {
    		throw new Exception("No Email Template");
    	}
    	//body y subject
    	String body;
    	String subject;
    	if(locale == null){
    		Builder b = new Builder();
			b.setLanguage("ES");
			Locale a = b.build();
			locale = a;
    	}
    	if (locale.getLanguage().equalsIgnoreCase("es")) {
    		body = template.getBody_es();
    		subject = template.getSubject_es();
    	} else {
    		body = template.getBody_en();
    		subject = template.getSubject_en();
    	}
    	
    	if (properties == null) {
    		properties = new HashMap<String, String>();
    	}
    	if (user != null) {    		
    		properties.put("email", user.getEmail());
    		properties.put("name", user.getFullName());
    		properties.put("passwordhint", user.getPasswordHint());
    		properties.put("username", user.getUsername());
    		properties.put("logintype", user.getLoginType().toString());    	
    	}
    	
    	//Reemplazar properties y usuario
    	subject = this.replaceProperties(subject, properties);
    	body = this.replaceProperties(body, properties);
    	
    	MimeMessage mimeMessage = ((JavaMailSenderImpl) mailSender).createMimeMessage();
    	MimeMessageHelper msg = new MimeMessageHelper(mimeMessage, false, "utf-8");
    	msg.setFrom(defaultFrom);
    	msg.setTo(to);
    	msg.setSubject(subject);
    	msg.getMimeMessage().setText(body,  "utf-8", "text/html");
    	msg.setText(body, true);
    	msg.setSentDate(new Date());
    	if (attachments != null) {    		
    		for (String file : attachments.keySet()) {			
    			msg.addAttachment(file, new ByteArrayResource(attachments.get(file)));
    		}
    	}
    	
    	if (user != null){    		
    		log.debug("Send email: " + mail + " to " + user.getFullName() + " (" + user.getEmail() + ")");
    	}
    	

    	((JavaMailSenderImpl) mailSender).send(mimeMessage);
    }
    
    private String replaceProperties(String message, Map<String, String> properties) {
    	for (Entry<String, String> p : properties.entrySet()) {
    		String key = p.getKey();
			message = message.replaceAll("\\$" + key + "\\$", p.getValue());
		}
    	return message;    	
    }

    /**
     * Send a simple message with pre-populated values.
     * @param msg the message to send
     * @throws org.springframework.mail.MailException when SMTP server is down
     */
    public void send(SimpleMailMessage msg) throws MailException {
    	if(StartupListener.isEnabledConfig(ConstantsType.TESTING_SYSTEM)) {
    		msg.setTo(StartupListener.getConfigValue(ConstantsType.TESTING_EMAIL_RECIPIENT));
    	}
    	
        try {
            mailSender.send(msg);
        } catch (MailException ex) {
            log.error(ex.getMessage());
            throw ex;
        }
    }

    /**
     * Convenience method for sending messages with attachments.
     * 
     * @param recipients array of e-mail addresses
     * @param sender e-mail address of sender
     * @param resource attachment from classpath
     * @param bodyText text in e-mail
     * @param subject subject of e-mail
     * @param attachmentName name for attachment
     * @throws MessagingException thrown when can't communicate with SMTP server
     */
    public void sendMessage(String[] recipients, String sender, 
                            ClassPathResource resource, String bodyText,
                            String subject, String attachmentName)
    throws MessagingException {
        MimeMessage message = ((JavaMailSenderImpl) mailSender).createMimeMessage();

        // use the true flag to indicate you need a multipart message
        MimeMessageHelper helper = new MimeMessageHelper(message, true);

        helper.setTo(recipients);
        if(StartupListener.isEnabledConfig(ConstantsType.TESTING_SYSTEM)) {
        	helper.setTo(StartupListener.getConfigValue(ConstantsType.TESTING_EMAIL_RECIPIENT));
    	}

        // use the default sending if no sender specified
        if (sender == null) {
            helper.setFrom(defaultFrom);
        } else {
           helper.setFrom(sender);
        }

        helper.setText(bodyText);
        helper.setSubject(subject);

        helper.addAttachment(attachmentName, resource);

        ((JavaMailSenderImpl) mailSender).send(message);
    }
}
